﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using Cemit.PolyProto;
using Google.Protobuf;

namespace Cemit.NetFramework
{
    [System.Obsolete("已过时，使用帧同步框架进行输入同步")]
    sealed class PolyInputManager : MonoBehaviour, INetInputManager
    {
        public static PolyInputManager Instances => _Instances ? _Instances : Create();

        Dictionary<string, KeyInputListener> keyInputListeners;
        Dictionary<string, BottonInputListener> bottonInputListeners;

        static PolyInputManager _Instances;

        bool m_IsPlayerCreated = false;

        [Obsolete]
        static Dictionary<string, InputData> playerInputDatas = new Dictionary<string, InputData>();

        private void Awake()
        {
            keyInputListeners = new Dictionary<string, KeyInputListener>();
            bottonInputListeners = new Dictionary<string, BottonInputListener>();

            //添加接收输入消息监听
            PolyNetwork.AddMessageListener<Msg_Lobby_KeyInput>(OnMsgInputReceive);
            //PolyNetwork.AddMessageListener<MsgBottonInput>(OnMsgInputReceive);

            //在创建角色成功时启动本地按键监听，并在服务器关闭时关闭
            PolyNetwork.OnCreatePlayerSucceeded += () => m_IsPlayerCreated = true;
            PolyNetwork.OnClosed += () => m_IsPlayerCreated = false;
        }

        private void Start()
        {
            DontDestroyOnLoad(_Instances);
        }

        private void Update()
        {
            //检测按键状态并发送至服务器
            if (m_IsPlayerCreated)
            {
                CheckAndSendKeyMsg();
                //CheckAndSendBottonMsg();
            }
        }

        /// <summary>
        /// 检查按键输入情况，并将状态变更发送到服务器
        /// </summary>
        [Obsolete("使用帧同步框架（TODO）进行案件同步")]
        private static void CheckAndSendKeyMsg()
        {
            foreach (KeyCode item in PolyNetwork.Settings.netInputKey)
            {
                if (Input.GetKeyDown(item))
                {
                    SendKeyMsg(item, InputState.down);
                }
                else if (Input.GetKeyUp(item))
                {
                    SendKeyMsg(item, InputState.up);
                }
            }

            void SendKeyMsg(KeyCode key, InputState state)
            {
                //PolyNetwork.Send(new Msg_Lobby_KeyInput
                //{
                //    PlayerId = PolyNetwork.Player.ID,
                //    Key = (int)key,
                //    State = (Msg_Lobby_KeyInput.Types.KeyState)state
                //});
            }
        }

        //发送按钮（InputManager管理的按钮）已过时，直接使用CheckAndSendKeyMsg() LANQ 2019/9/10
        //[Obsolete]
        //private static void CheckAndSendBottonMsg()
        //{
        //    foreach (string item in PolyNetwork.Settings.netInputBotton)
        //    {
        //        if (Input.GetButtonDown(item))
        //        {
        //            SendBottonMsg(item, InputState.down);
        //        }
        //        else if (Input.GetButtonUp(item))
        //        {
        //            SendBottonMsg(item, InputState.up);
        //        }
        //    }

        //    void SendBottonMsg(string boton, InputState state)
        //    {
        //        PolyNetwork.Send(new MsgBottonInput
        //        {
        //            PlayerId = PolyNetwork.Player.ID,
        //            Botton = boton,
        //            State = (MsgBottonInput.Types.KeyState)state
        //        });
        //    }
        //}

        /// <summary>
        /// 创建一个PolyInputManager游戏对象
        /// </summary>
        public static PolyInputManager Create()
        {
            PolyInputManager[] instances = FindObjectsOfType<PolyInputManager>();

            if (instances.Length > 1)
            {
                throw new Exception("存在多个PolyInputManager！请只保留一个！");
            }
            if (instances.Length == 1)
            {
                _Instances = instances[0];
                return _Instances;
            }

            //创建一个
            GameObject @object = new GameObject();
            _Instances = @object.AddComponent<PolyInputManager>();

            return _Instances;
        }

        /// <summary>
        /// 添加某个按键状态发生变化的监听
        /// </summary>
        public void SetKeyInputListener(string playerId, KeyInputListener listener)
        {
            if (!keyInputListeners.ContainsKey(playerId))
            {
                keyInputListeners.Add(playerId, listener);
                return;
            }

            keyInputListeners[playerId] = listener;
        }

        /// <summary>
        /// 添加某个按钮状态发生变化的监听
        /// </summary>
        [Obsolete("请使用[SetKeyInputListener()]")]
        public void SetBottonInputListener(string playerId, BottonInputListener listener)
        {
            if (!bottonInputListeners.ContainsKey(playerId))
            {
                bottonInputListeners.Add(playerId, listener);
                return;
            }

            bottonInputListeners[playerId] = listener;
        }

        private void OnMsgInputReceive(IMessage message)
        {
            switch (message)
            {
                case Msg_Lobby_KeyInput key:
                    if (!keyInputListeners.ContainsKey(key.PlayerId))
                    {
                        Debug.LogError("收到未注册的角色按键信息，角色ID：" + key.PlayerId);
                        break;
                    }

                    keyInputListeners[key.PlayerId]?.Invoke((KeyCode)key.Key, (InputState)key.State);
                    break;

                //发送按键已过时 LANQ 2019/9/10
                //case MsgBottonInput botton:
                //    if (!bottonInputListeners.ContainsKey(botton.PlayerId))
                //    {
                //        PolyNetwork.Debug.LogError("收到未注册的角色按键信息，角色ID：" + botton.PlayerId);
                //        break;
                //    }
                //    bottonInputListeners[botton.PlayerId]?.Invoke(botton.Botton, (InputState)botton.State);
                //    break;

                default:
                    Debug.Log("收到未知的按键输入信息：" + message.GetType());
                    break;
            }
        }

        [Obsolete("请使用SetKeyInputListener()或SetBottonInputListener()")]
        public static void AddPlayerListener(string playerId)
        {
            playerInputDatas.Add(playerId, new InputData());
        }

        [Obsolete("请使用SetKeyInputListener()或SetBottonInputListener()")]
        public static bool GetBotton(string playerId, string botton)
        {
            if (!playerInputDatas.TryGetValue(playerId, out InputData inputData))
            {
                return false;
            }
            if (!inputData.bottonInputs.TryGetValue(botton, out bool ret))
            {
                return false;
            }

            return ret;
        }

        [Obsolete("请使用SetKeyInputListener()或SetBottonInputListener()")]
        public static bool GetKey(string playerId, KeyCode keyCode)
        {
            if (!playerInputDatas.TryGetValue(playerId, out InputData inputData))
            {
                return false;
            }
            if (!inputData.keyInputs.TryGetValue(keyCode, out bool ret))
            {
                return false;
            }

            return ret;
        }

        [Obsolete]
        private static bool ContainsKey<T, F>(Dictionary<T, Dictionary<F, bool>> pairs, T key0, F key1)
        {
            if (!pairs.ContainsKey(key0))
            {
                return false;
            }
            if (!pairs[key0].ContainsKey(key1))
            {
                return false;
            }

            return true;
        }

        [Obsolete]
        class InputData
        {
            public Dictionary<KeyCode, bool> keyInputs = new Dictionary<KeyCode, bool>();
            public Dictionary<string, bool> bottonInputs = new Dictionary<string, bool>();
            public Action<InputState> OnKeyStateChange = null;
            public Action<InputState> OnBottonStateChange = null;
        }
    }
}
